/*
 * Copyright (C) 2007-2008  Hylke van der Schaaf
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, in version 3 of the License.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package hextd.tower;

import hextd.creep.Factory;
import hextd.creep.Creep;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;

public class CreepCompare {

	public static class CompareFast implements Comparator<Creep> {

		@Override
		public int compare(Creep e1, Creep e2) {
			if (e1 == null && e2 == null) {
				return 0;
			}
			if (e1 == e2) {
				return 0;
			}
			if (e1 == null) {
				return -1;
			}
			if (e2 == null) {
				return 1;
			}

			float e1f, e2f;
			e1f = e1.getSpeed();
			e2f = e2.getSpeed();
			if (e1f != e2f) {
				return Float.compare(e1f, e2f);
			}

			e1f = e1.getProgress();
			e2f = e2.getProgress();
			if (e1f != e2f) {
				return Float.compare(e1f, e2f);
			}

			long e1l, e2l;
			e1l = e1.getHealth();
			e2l = e2.getHealth();
			if (e1l != e2l) {
				return (int) (e1l - e2l);
			}

			int e1i, e2i;
			e1i = e1.getPathId();
			e2i = e2.getPathId();
			if (e1i != e2i) {
				return (int) (e1i - e2i);
			}

			if (!e2.getType().equals(e1.getType())) {
				return Factory.identifyEnemy(e1.getType()).compareTo(Factory.identifyEnemy(e2.getType()));
			}
			if (e1.getOwner() != e2.getOwner()) {
				return e1.getOwner() - e2.getOwner();
			}

			e1i = e1.getUniqueId();
			e2i = e2.getUniqueId();
			if (e1i != e2i) {
				return (int) (e1i - e2i);
			}
			System.out.println("CreepCompare::CompareFast:compare: creeps seem the same, but should not!");
			return -1;
		}
	}

	public static class CompareFurthest implements Comparator<Creep> {

		@Override
		public int compare(Creep e1, Creep e2) {
			if (e1 == null && e2 == null) {
				return 0;
			}
			if (e1 == e2) {
				return 0;
			}
			if (e1 == null) {
				return -1;
			}
			if (e2 == null) {
				return 1;
			}

			float e1f, e2f;
			e1f = e1.getProgress();
			e2f = e2.getProgress();
			if (e1f != e2f) {
				return Float.compare(e1f, e2f);
			}

			e1f = e1.getSpeed();
			e2f = e2.getSpeed();
			if (e1f != e2f) {
				return Float.compare(e1f, e2f);
			}

			long e1h, e2h;
			e1h = e1.getHealth();
			e2h = e2.getHealth();
			if (e2h != e1h) {
				return (int) (e2h - e1h);
			}

			int e1i, e2i;
			e1i = e1.getPathId();
			e2i = e2.getPathId();
			if (e1i != e2i) {
				return (int) (e1i - e2i);
			}

			if (!e2.getType().equals(e1.getType())) {
				return Factory.identifyEnemy(e1.getType()).compareTo(Factory.identifyEnemy(e2.getType()));
			}
			if (e1.getOwner() != e2.getOwner()) {
				return e1.getOwner() - e2.getOwner();
			}

			e1i = e1.getUniqueId();
			e2i = e2.getUniqueId();
			if (e1i != e2i) {
				return (int) (e1i - e2i);
			}

			System.out.println("CreepCompare::CompareFurthest:compare: creeps seem the same, but should not!");
			return -1;
		}
	}

	public static class CompareHard implements Comparator<Creep> {

		@Override
		public int compare(Creep e1, Creep e2) {
			if (e1 == null && e2 == null) {
				return 0;
			}
			if (e1 == e2) {
				return 0;
			}
			if (e1 == null) {
				return -1;
			}
			if (e2 == null) {
				return 1;
			}

			long e1h, e2h;
			e1h = e1.getHealth();
			e2h = e2.getHealth();
			if (e1h != e2h) {
				return (int) (e1h - e2h);
			}

			float e1f, e2f;
			e1f = e1.getProgress();
			e2f = e2.getProgress();
			if (e1f != e2f) {
				return Float.compare(e1f, e2f);
			}

			e1f = e1.getSpeed();
			e2f = e2.getSpeed();
			if (e1f != e2f) {
				return Float.compare(e1f, e2f);
			}

			int e1i, e2i;
			e1i = e1.getPathId();
			e2i = e2.getPathId();
			if (e1i != e2i) {
				return (int) (e1i - e2i);
			}

			if (!e2.getType().equals(e1.getType())) {
				return Factory.identifyEnemy(e1.getType()).compareTo(Factory.identifyEnemy(e2.getType()));
			}
			if (e1.getOwner() != e2.getOwner()) {
				return e1.getOwner() - e2.getOwner();
			}

			e1i = e1.getUniqueId();
			e2i = e2.getUniqueId();
			if (e1i != e2i) {
				return (int) (e1i - e2i);
			}
			System.out.println("CreepCompare::CompareHard:compare: creeps seem the same, but should not!");
			return -1;
		}
	}

	public static class CompareWeak implements Comparator<Creep> {

		@Override
		public int compare(Creep e1, Creep e2) {
			if (e1 == null && e2 == null) {
				return 0;
			}
			if (e1 == e2) {
				return 0;
			}
			if (e1 == null) {
				return -1;
			}
			if (e2 == null) {
				return 1;
			}

			long e1l, e2l;
			e1l = e1.getHealth();
			e2l = e2.getHealth();
			if (e1l != e2l) {
				return (int) (e2l - e1l);
			}

			float e1f, e2f;
			e1f = e1.getProgress();
			e2f = e2.getProgress();
			if (e1f != e2f) {
				return Float.compare(e1f, e2f);
			}

			e1f = e1.getSpeed();
			e2f = e2.getSpeed();
			if (e1f != e2f) {
				return Float.compare(e1f, e2f);
			}

			int e1i, e2i;
			e1i = e1.getPathId();
			e2i = e2.getPathId();
			if (e1i != e2i) {
				return (int) (e1i - e2i);
			}

			if (!e2.getType().equals(e1.getType())) {
				return Factory.identifyEnemy(e1.getType()).compareTo(Factory.identifyEnemy(e2.getType()));
			}
			if (e1.getOwner() != e2.getOwner()) {
				return e1.getOwner() - e2.getOwner();
			}

			e1i = e1.getUniqueId();
			e2i = e2.getUniqueId();
			if (e1i != e2i) {
				return (int) (e1i - e2i);
			}
			System.out.println("CreepCompare::CompareWeak:compare: creeps seem the same, but should not!");
			return -1;
		}
	}

	public static Creep[] findLargestSet(Collection<Creep> enemies, int number, float x, float y, float r, Comparator<Creep> c, Creep[] exclude, boolean exShielded) {
		Creep[] retval = new Creep[number];
		float r2 = r * r;
		int foundCount = 0;
		int smallestPointer = number - 1;
		Arrays.sort(exclude, c);
		for (Creep e : enemies) {
			if (!e.validTarget() || (exShielded && e.isShielded())) {
				continue;
			}
			float dx = e.getX() - x;
			float dy = e.getY() - y;
			if (dx * dx + dy * dy > r2) {
				continue;
			}
			int index = Arrays.binarySearch(exclude, e, c);
			if (index < 0) {
				if (foundCount > 0) {
					if (foundCount < number || c.compare(e, retval[smallestPointer]) > 0) {
						index = Arrays.binarySearch(retval, e, c);
						int insertIndex = -index - 2;
						System.arraycopy(retval, 1, retval, 0, insertIndex);
						retval[insertIndex] = e;
						foundCount++;
						if (smallestPointer > 0) {
							smallestPointer--;
						}
					}
				} else {
					retval[smallestPointer] = e;
					foundCount = 1;
				}
			}

		}

		if (foundCount < number) {
			Creep[] tempRetVal = new Creep[foundCount];
			System.arraycopy(retval, smallestPointer, tempRetVal, 0, foundCount);
			return tempRetVal;
		}
		return retval;
	}

	public static Creep findLargestSingle(Collection<Creep> enemies, float x, float y, float r, Comparator<Creep> c, Creep prefered, boolean exShielded) {
		float r2 = r * r;
		if (prefered != null) {
			if (prefered.validTarget() && !(exShielded && prefered.isShielded())) {
				float dx = prefered.getX() - x;
				float dy = prefered.getY() - y;
				if (dx * dx + dy * dy < r2) {
					return prefered;
				}
			}
		}
		Creep target = null;

		for (Creep e : enemies) {
			if (!e.validTarget() || (exShielded && e.isShielded())) {
				continue;
			}
			float dx = e.getX() - x;
			float dy = e.getY() - y;
			if (dx * dx + dy * dy > r2) {
				continue;
			}
			if (c.compare(e, target) > 0) {
				target = e;
			}
		}
		return target;
	}
}